﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Data;
using System.Diagnostics;
using System.Text.RegularExpressions;

using System.Linq;
using System.Text;

//netoffice-api
using VBE = NetOffice.VBIDEApi;
using office = NetOffice.OfficeApi;
using 代码模块 = NetOffice.VBIDEApi.CodeModule;
using 代码窗格 = NetOffice.VBIDEApi.CodePane;
using 插件对象 = NetOffice.VBIDEApi.AddIn;
using 模块类型 = NetOffice.VBIDEApi.Enums.vbext_ComponentType;
using 菜单栏 = NetOffice.OfficeApi.CommandBar;
using 菜单栏按钮 = NetOffice.OfficeApi.CommandBarButton;
using 菜单栏控件 = NetOffice.OfficeApi.CommandBarControl;
using 菜单栏菜单 = NetOffice.OfficeApi.CommandBarPopup;
using 过程类型 = NetOffice.VBIDEApi.Enums.vbext_ProcKind;

//microsoftoffice-api
//using VBE = Microsoft.Vbe.Interop;
//using office = Microsoft.Office.Core;
//using 代码模块 = Microsoft.Vbe.Interop.CodeModule;
//using 代码窗格 = Microsoft.Vbe.Interop.CodePane;
//using 插件对象 = Microsoft.Vbe.Interop.AddIn;
//using 模块类型 = Microsoft.Vbe.Interop.vbext_ComponentType;
//using 菜单栏 = Microsoft.Office.Core.CommandBar;
//using 菜单栏按钮 = Microsoft.Office.Core.CommandBarButton;
//using 菜单栏控件 = Microsoft.Office.Core.CommandBarControl;
//using 菜单栏菜单 = Microsoft.Office.Core.CommandBarPopup;
//using 过程类型 = Microsoft.Vbe.Interop.vbext_ProcKind;
using System.Threading.Tasks;

//using static 枸杞VBE插件.代码库.代码库助手;
using static 枸杞VBE插件.命令;
using 枸杞VBE插件.代码格式化;

using NetOffice.VBIDEApi;
using NetOffice.OfficeApi;

using static 枸杞VBE插件.代码库.代码库助手;
using System.Reflection;
using System.IO;
using System.Runtime.InteropServices.ComTypes;

namespace 枸杞VBE插件
{
    internal partial class VBE助手 : IDisposable //: Rougamo.IRougamo<LoggingAttribute>,
    {
        internal VBE.VBE VBE对象;
        internal VBE.AddIn Addin;
        internal 菜单栏 主菜单栏;
        internal 菜单栏 右键菜单;
        internal 键盘鼠标钩子 键盘钩子;
        internal IntPtr MDIClient句柄;
        internal Dictionary<string, 菜单栏控件> 控件字典;
        internal Lazy<窗体.代码库窗体> 代码库窗体;
        internal Lazy<破解工程密码> 破解工程密码;
        internal Lazy<Indenter> Indenter;
        internal int 标签号;

        [Info]
        internal void 初始化()
        {
            // if (VBE助手实例 == null || VBE助手实例.Disposed) VBE助手实例 = new VBE助手();
            代码库窗体 = new Lazy<窗体.代码库窗体>();
            破解工程密码 = new Lazy<破解工程密码>();
            Indenter = new Lazy<Indenter>(() => new Indenter(VBE对象));
            MDIClient句柄 = WinApi.FindWindowEx((IntPtr)VBE对象.MainWindow.HWnd, IntPtr.Zero, "MDIClient", "");
            键盘钩子 = new 键盘鼠标钩子();
            控件字典 = new Dictionary<string, 菜单栏控件>();
            Db = CreateDatabase();// new LiteDB.LiteDatabase($"Filename ={数据库地址}; Password = 1234");
            生成右键菜单();
            生成主菜单栏();
            主菜单添加一级菜单();
            主菜单栏.Visible = true;
            主菜单添加次级控件();
        }

        [Info]
        internal void 生成右键菜单()
        {
            右键菜单 = VBE对象.CommandBars["Code Window"];
            右键菜单.Controls.添加按钮("删除空行", 3411, 删除空行).Move(null, 1);
            右键菜单.Controls.添加按钮("格式化当前模块", 3495, 格式化当前模块).Move(null, 1).BeginGroup = true;

            //右键菜单.Controls.添加按钮("格式化当前过程", 3, 3495, (菜单栏按钮 按钮, ref bool b) => 格式化当前过程());
            //菜单栏控件 剪切控件 = 右键菜单.Controls["剪切(&T)"];
            //剪切控件.BeginGroup = true;
            //右键菜单.Controls[3].BeginGroup = true;
        }

        [Info]
        internal void 生成主菜单栏()
        {
            if (主菜单栏 == null)
            {
                主菜单栏 = VBE对象.CommandBars.Add("枸杞VBE工具栏", office.Enums.MsoBarPosition.msoBarTop, null, true);
                控件字典["枸杞VBE工具栏"] = null;
                主菜单栏.Enabled = true;
                主菜单生成基础功能按钮();
            }
        }

        [Info]
        internal void 主菜单添加一级菜单()
        {
            查询一级菜单().ForEach(代码 => 生成控件(代码.关键字, 控件类型.菜单));
        }

        [Info]
        internal void 主菜单添加次级控件()
        {
            查询次级控件().ForEach(a => 生成控件(a.关键字, a.计数 > 1 ? 控件类型.菜单 : 控件类型.按钮));
        }

        [Debug]
        internal 菜单栏控件 生成控件(string 关键字, 控件类型 控件类型)
        {
            try { if (控件字典.ContainsKey(关键字)) 控件字典[关键字].Delete(); } catch { }            //上级控件先删除导致后面的删除会报错,直接无视掉
            string 上级关键字 = 上级(关键字);
            string 本级关键字 = 本级(关键字);
            office.CommandBarControls Controls;
            if (上级关键字 == "枸杞VBE工具栏")
            {
                Controls = 主菜单栏.Controls;
            }
            else
            {
                菜单栏菜单 上级菜单;
                if (!控件字典.ContainsKey(上级关键字))
                {
                    代码库.代码库助手.更新代码(new 代码库.代码库助手.代码() { 关键字 = 上级关键字 });
                    上级菜单 = (菜单栏菜单)生成控件(上级关键字, 控件类型.菜单);
                }
                else
                {
                    上级菜单 = (菜单栏菜单)控件字典[上级关键字];
                }
                Controls = 上级菜单.Controls;
            }
            菜单栏控件 控件;
            if (控件类型 == 控件类型.按钮)
            {
                控件 = Controls.添加按钮(本级关键字, 1, 按钮事件, 关键字);
            }
            else
            {
                控件 = Controls.添加菜单(本级关键字, 关键字);
            }
            控件.Parameter = 关键字;
            return 控件;
        }

        [Info]
        internal void 主菜单生成基础功能按钮()
        {
            主菜单栏.Controls.添加按钮("代码库", 1, 显示代码库窗体, "代码库");
            菜单栏菜单 选项菜单 = 主菜单栏.Controls.添加菜单("选项");
            var cs = 选项菜单.Controls;
            cs.添加按钮("格式化当前过程", 1, 格式化当前过程, @"选项\格式化当前过程");
            cs.添加按钮("格式化当前模块", 1, 格式化当前模块, @"选项\格式化当前模块");
            cs.添加按钮("格式化当前工程", 1, 格式化当前工程, @"选项\格式化当前工程");
            cs.添加按钮("无视密码", 1, 无视工程密码, @"选项\无视密码");
            cs.添加按钮("恢复密码", 1, 恢复密码, @"选项\恢复密码");
            cs.添加按钮("打开Logs文件夹", 1, 打开logs文件夹, @"选项\打开logs文件夹");
            cs.添加按钮("测试引用", 1, (菜单栏按钮 c, ref bool _) =>
            {
                VBE对象.ActiveVBProject.References.AddFromFile(Path.Combine(配置.插件路径, "枸杞VBE插件.tlb"));
                VBE对象.ActiveVBProject.VBComponents
                .Add(模块类型.vbext_ct_StdModule)
                .CodeModule
                .AddFromString("Sub test()\nDim obj As 枸杞VBE插件.VBEAddin\nSet obj = Application.VBE.AddIns(\"枸杞VBE插件\").Object\nobj.msg\nEnd Sub");
            }, @"选项\测试引用");
        }

        #region IDisposable接口实现

        private bool Disposed;

        private static VBE助手 _VBE助手实例;

        public static VBE助手 VBE助手实例
        {
            get
            {
                if (_VBE助手实例 == null || _VBE助手实例.Disposed)
                {
                    _VBE助手实例 = new VBE助手();
                }
                return _VBE助手实例;
            }
        }

        private VBE助手()//初始化
        {
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (Disposed)
            {
                return;
            }
            //清理托管资源
            if (disposing)
            {
                键盘钩子?.Dispose();
                Db?.Dispose();
                破解工程密码.IsValueCreated.Run(破解工程密码.Value.Dispose);
                代码库窗体.IsValueCreated.Run(代码库窗体.Value.Dispose);
                //if (ManagedResource != null)
                //{
                //    ManagedResource = null;
                //}
            }
            //清理非托管资源
            //控件字典.ToList().ForEach(kv =>
            //{
            //    var value = kv.Value;
            //    if (value.Type == office.Enums.MsoControlType.msoControlButton)
            //    {
            //        value.Delete();
            //        value.Dispose();
            //    }
            //});
            控件字典["删除空行"].Delete();
            控件字典["删除空行"].Dispose();
            控件字典["格式化当前模块"].Delete();
            控件字典["格式化当前模块"].Dispose();
            主菜单栏.DisposeChildInstances(true);
            主菜单栏.Delete();
            主菜单栏.Dispose();
            右键菜单.Reset();
            右键菜单.DisposeChildInstances();
            右键菜单.Dispose();
            VBE对象.DisposeChildInstances();
            VBE对象.Dispose();
            GC.Collect();

            //if (NativeResource != IntPtr.Zero)
            //{
            //System.Runtime.InteropServices.Marshal.FreeHGlobal(NativeResource);
            //System.Runtime.InteropServices.Marshal.FinalReleaseComObject
            //    //NativeResource = IntPtr.Zero;
            //}
            //告诉自己已经被释放
            Disposed = true;
        }

        ~VBE助手()
        {
            //必须为false
            Dispose(false);
        }

        #endregion IDisposable接口实现
    }
}